﻿using AntiVmDetection.Interface;
using AntiVmDetection.Utils;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;

namespace AntiVmDetection.Impl
{
    class VmwareDetection : IDetection
    {
        #region ==== 检测方法映射 ====

        delegate bool DetectionMethod();
        struct DetectionMap
        {
            public string info;
            public DetectionMethod method;

            public DetectionMap(string info, DetectionMethod method)
            {
                this.info = info;
                this.method = method;
            }
        }
        static readonly DetectionMap[] DetectionMaps = {
            new DetectionMap("BIOS Detection", BIOSDetection),
            new DetectionMap("Services Detection", ServiceDetection),
            new DetectionMap("Processes Detection", ProcessDetection),
            new DetectionMap("I/O Detection", IODetection),
            new DetectionMap("CPUID Detection", CpuidDetection),
            new DetectionMap("Scsi Detection", ScsiDetection),
            new DetectionMap("BCD Detection", BcdDetection),
        };
        #endregion

        #region ==== 检测静态数据 ====

        static readonly string BIOSKey = @"HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\BIOS";
        static readonly Dictionary<string, dynamic> BiosKeyMap = new Dictionary<string, dynamic>()
        {
            {"BIOSVendor", "VMware"},
            {"BIOSVersion", "VM"},
            {"SystemManufacturer", "VMware"},
            {"SystemProductName", "VMware"},
        };
        static readonly string ScsiKey = @"HARDWARE\DEVICEMAP\Scsi";
        static readonly string ScsiSub = @"\Scsi Bus 0\Target Id 0\Logical Unit Id 0";
        static readonly HashSet<string> DetectionServices = new HashSet<string>()
        {
            "VGAuthService",
            "vmvss",        
            "VMTools",      
            "vm3dservice",      
        };
        static readonly HashSet<string> DetectionProcesses = new HashSet<string>()
        {
            "VGAuthService",
            "vmtoolsd",
            "vm3dservice",
        };
        static readonly string BcdKey = @"BCD00000000\Objects";
        static readonly string BcdSubKey = @"\Elements\12000004";
        #endregion
        
        #region ==== 检测方法 ====

        private static bool BIOSDetection()
        {
            object systemBiosVersion = Registry.GetValue(@"HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System", "SystemBiosVersion", null);
            if (systemBiosVersion != null)
            {
                string data = string.Join("",(string[])systemBiosVersion);
                if (data.Contains("VMware, Inc."))
                    return true;
            }

            foreach (var item in BiosKeyMap)
            {
                if (Registry.GetValue(BIOSKey, item.Key, null).ToString().StartsWith(item.Value))
                    return true;
            }
            return false;
        }
        private static bool ScsiDetection()
        {
            RegistryKey scsiKey = Registry.LocalMachine.OpenSubKey(ScsiKey);
            if (scsiKey == null)
                return false;

            string[] subKeyNames = scsiKey.GetSubKeyNames();
            foreach (var subKeyName in subKeyNames)
            {
                RegistryKey scsiLogical = scsiKey.OpenSubKey(subKeyName + ScsiSub);
                if (scsiLogical == null)
                    continue;

                if (scsiLogical.GetValue("SerialNumber", "").ToString().StartsWith("VMWare"))
                    return true;
            }
            return false;
        }
        private static bool ServiceDetection()
        {
            ServiceController[] services = ServiceController.GetServices();
            foreach (var service in services)
            {
                if (DetectionServices.Contains(service.ServiceName))
                    return true;
            }
            return false;
        }
        private static bool ProcessDetection()
        {
            Process[] processes = Process.GetProcesses();
            foreach (var process in processes)
            {
                if (DetectionProcesses.Contains(process.ProcessName))
                    return true;
            }
            return false;
        }
        private static bool IODetection()
        {
            uint[] @out = new uint[4];
            return Winapi.VmwareCall(@out, 1, 0, 0);
        }
        private static bool CpuidDetection()
        {
            int[] @out = new int[4];
            Winapi.Cpuid(@out, 0x40000000, 0);
            foreach (var item in @out)
            {
                if (item != 0)
                    return true;
            }
            return false;
        }
        private static bool BcdDetection()
        {
            RegistryKey bcdKey = Registry.LocalMachine.OpenSubKey(BcdKey);
            if (bcdKey == null)
                return false;

            string[] subKeyNames = bcdKey.GetSubKeyNames();
            foreach (var subKeyName in subKeyNames)
            {
                RegistryKey bcdDetal = bcdKey.OpenSubKey(subKeyName + BcdSubKey);
                if (bcdDetal == null)
                    continue;

                if (bcdDetal.GetValue("Element", "").ToString().StartsWith("EFI VMware"))
                    return true;
            }
            return false;
        }
        #endregion
        public void PrintDetection()
        {
            char status;
            foreach (var item in DetectionMaps)
            {
                if (item.method())
                    status = '+';
                else
                    status = '-';
                Console.WriteLine($"[{status}] {item.info}");
            }
        }
        public bool Detection()
        {
            foreach (var detection in DetectionMaps)
            {
                if (detection.method())
                    return true;
            }
            return false;
        }
    }
}
